package org.springframework.web.servlet.ajax.json;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class JsonAjaxImpl implements JsonAjax {

	public static final String JAVASCRIPT_KEY = "javascript";
	
	//We don't want to parameterize the map, because a developer
	//might want to add none <String, String> information into the map.
	//We expect this map to be serialized into JSON, either by our class
	//our by some other means that the developer chooses.
	//Need a LinkedHashMap here because order may matter, for example if one
	//html div is supposed to be written inside another html div.
	private LinkedHashMap map = new LinkedHashMap();
	//TODO Need a setter.
	private PartialsCore partialsCore;


	public void setPartialsCore(PartialsCore partials) {
		this.partialsCore = partials;
	}


	public void writeJsonRedirect(String relativePath){
		partialsCore.writeJsonRedirect(relativePath,
				AjaxContext.getRequest(),  AjaxContext.getResponse());
	}

	public void addJavascript(String javascript){
		addJavascriptInternal(javascript);
	}
	
	public void addJavascript(String viewName, Map modelMap){
		addPartials(JAVASCRIPT_KEY, viewName, modelMap);
	}

	public LinkedHashMap addPartials(String keys, String viewNames, Map modelMap){
		List<String> keyList = Arrays.asList(keys.split(LIST_DELIMITER));
		List<String> viewNamesList = Arrays.asList(viewNames.split(LIST_DELIMITER));
		return addPartials(keyList, viewNamesList, modelMap);
	}
	public LinkedHashMap addPartials(List<String> keys, List<String> viewNames, Map modelMap){
		if(keys.size() != viewNames.size())
			throw new IllegalArgumentException("Keys and viewNames are not of the same size.");
		LinkedHashMap newMap = partialsCore.makeMap(keys, viewNames, modelMap,
				AjaxContext.getRequest(),  AjaxContext.getResponse());
		if(keys.size() == 1 && JAVASCRIPT_KEY.equals(keys.get(0))){
			addJavascriptInternal((String) newMap.get(JAVASCRIPT_KEY));
		}else
			map.putAll(newMap);
		return newMap;
	}
	
	private void addJavascriptInternal(String newJavascript){
		String javascriptSoFar = (String) map.get(JAVASCRIPT_KEY);
		javascriptSoFar = (javascriptSoFar == null) ? "" : javascriptSoFar;
		javascriptSoFar = javascriptSoFar + newJavascript;
		map.put(JAVASCRIPT_KEY, javascriptSoFar);		
	}

	//Can be used both to get the map and to add to it.
	//This is info that we expect will be serialized, and of course it
	//may be that client code takes this map and does the json serialization itself.
	public LinkedHashMap getMap(){
		return map;
	}

	//For now we'll assume that we've already got the map, that the developer has
	//added to it if neccesarry by calling getMap(), and wants us to use that map.
	//Of course the developer could just getMap() and use his own json serializtion
	//mechanism.
	public String toJson(){
		return partialsCore.getJsonSerializer().mapToJson(map);
	}

	public void writeJson(){
		partialsCore.write(AjaxContext.getResponse(), toJson());
	}

	@Override
	protected void finalize() throws Throwable {
		this.partialsCore = null;
		super.finalize();
	}

}
